<html>
<head>
<title>CpcPaChi - Version 0.07</title>
<style type="text/css">
span {
  font-family: 'Courier New';
  font-size: 10pt;
  color: #000000;
}
.sc0 {
  color: #808080;
}
.sc3 {
  color: #008080;
}
.sc4 {
  color: #FF8000;
}
.sc5 {
  font-weight: bold;
  color: #0000FF;
}
.sc7 {
  color: #808080;
}
.sc9 {
  color: #804000;
}
.sc10 {
  font-weight: bold;
  color: #000080;
}
.sc11 {
}
</style>
</head>
<body>
<h2>Un compilador sencillo paso a paso (7 - Primera tabla de s&iacute;mbolos)</h2>

<p align="right">(Volver al <a href="doc.html">&iacute;ndice</a>) </p>

<p>Los programas que reconoce nuestro compilador pueden tener instrucciones con o sin par&aacute;metros, pero hasta ahora esos par&aacute;metros s&oacute;lo pueden ser n&uacute;meros. En el "mundo real" esto no es as&iacute;, es muy frecuente necesitar trabajar con valores cambiantes, que se almacenar&aacute;n en variables.</p>

<p>Como primer acercamiento, vamos a hacer que nuestro compilador sea capaz de reconocer constantes, y en la pr&oacute;xima entrega ampliaremos para que tambi&eacute;n sean variables.</p>

<p>Existen distintos tipos de datos. Como nuestra m&aacute;quina de destino tiene un procesador de 8 bits, por ahora usaremos el m&aacute;s sencillo para nosotros: un tipo de datos Byte, que ocupe 1 byte en memoria y pueda almacenar un n&uacute;mero entero con un valor entre 0 y 255. Es algo limitado, pero que nos permitir&aacute; hacer proyectos peque&ntilde;os.</p>

<p>De cada constante necesitaremos varios datos: el nombre, el tipo de datos (por ahora s&oacute;lo "byte") y su valor. M&aacute;s adelante necesitaremos otros datos parecidos de cada variable (pero no guardaremos su valor actual, sino la direcci&oacute;n de memoria en que &eacute;ste se encuentra) y de cada funci&oacute;n.</p>

<p>Permitiremos que se pueda declarar varias constantes, separadas por comas. Todas tendr&aacute;n la forma "nombre = valor", comenzar&aacute;n con la palabra "const" y terminar&aacute;n con un punto y coma, de modo que un program sencillo podr&iacute;a ser as&iacute;:</p>

<pre><code>
program ej;
const linea = 10, columnaA = 10, columnaB = 1;
begin
  cpcMode(0);
  pen(2);
  paper(1);
  locate(columnaA, linea);
  writeChar( 'a' );
  pen(4);
  paper(3);
  locate ( columnaB ,  linea );
  writeChar('c');
end.
</code></pre>

<p>Cuando el analizador sint&aacute;ctico encuentre la palabra "const", deber&aacute; guardar informaci&oacute;n sobre la constante que se le indique (o las constantes, si son varias). Para ello, dentro del generador de c&oacute;digo crearemos una funci&oacute;n "insertarSimboloConst", que recibir&aacute; dos par&aacute;metros: el nombre y el valor, y una segunda funci&oacute;n "leerSimboloConst", que recibir&aacute; el nombre de la constante y devolver&aacute; su valor. Nuestra tabla de s&iacute;mbolos ser&aacute; rudimentaria: para no perder tiempo en crear estructuras de datos m&aacute;s eficientes, ser&aacute; simplemente un "array" de registros. Por tanto, para insertar un s&iacute;mbolo, recorreremos este array, a&ntilde;adiendo al final, o dando un mensaje de error si el s&iacute;mbolo est&aacute; repetido:</p>

<pre><code>
// Guardar una constante o variable en la tabla de s&amp;iacute;mbolos
public void Insertar(string nombre, tipoId tipo,
  tamDato tamanyo, int valorDir)
{
  nombre = nombre.ToUpper();
  // Primero comprobamos si el simbolo ya existe *)
  for (int i=0; i &lt; MAXSIMBOLOS; i++)
    if (listaSimbolos[i].nombre == nombre)
    {
      Console.WriteLine(&quot;Identificador ya definido: {0}&quot;, nombre);
      Environment.Exit(1);
    }

  // Si no existe (y cabe), lo insertamos
  if (numSimbolos &gt;= MAXSIMBOLOS - 1)
  {
      Console.WriteLine(&quot;Tabla de s&amp;iacute;mbolos llena!&quot;);
      Environment.Exit(1);
  }

  listaSimbolos[numSimbolos].nombre = nombre;
  listaSimbolos[numSimbolos].tamanyo = tamanyo;
  listaSimbolos[numSimbolos].tipo = tipo;
  listaSimbolos[numSimbolos].valorDir = valorDir;
  numSimbolos++;
}
</code></pre>


<p>Para leer un s&iacute;mbolo de nuestra tabla de s&iacute;mbolos sencilla, recorremos el array, y damos un mensaje en caso de que no exista:</p>

<pre><code>
public int LeerValor(string nombre)
{
  nombre = nombre.ToUpper();
  // Primero comprobamos si el simbolo ya existe *)
  for (int i=0; i &lt; MAXSIMBOLOS; i++)
    if (listaSimbolos[i].nombre == nombre)
    {
      return listaSimbolos[i].valorDir;
    }
  // Si no se ha devuelto valor es que no existe
  Console.WriteLine(&quot;Identificador inexistente: {0}&quot;, nombre);
  Environment.Exit(1);
  return 0;  // (No se llega nunca; necesario para que compile)
}
</code></pre>


<p>Ahora deber&iacute;amos modificar ligeramente las funciones que antes esperaban un par&aacute;metro num&eacute;rico, como CpcMode, para que esta vez reciban un identificador o un n&uacute;mero, si se trata de un identificador, deberemos buscar su valor en la tabla de s&iacute;mbolos. Lo podr&iacute;amos hacer as&iacute;:</p>

<pre><code>
void analizarCPCMODE()
{
  miLexer.LeerSimbolo('(');
  string cadenaTemp = miLexer.ObtenerEnteroOIdentificador();
  if ( (cadenaTemp[0] &gt;= '0') &amp;&amp; (cadenaTemp[0] &lt;= '9'))
    return Convert.ToInt32( cadenaTemp );
  else
    return LeerValor(cadenaTemp);
  int modo = miTablaSimb.LeerValorOConst(cadenaTemp);
  miLexer.LeerSimbolo(')');
  miLexer.LeerSimbolo(';');
  miGenerador.genCPCMODE( modo );
}
</code></pre>

<p>Como eso de comprobar si un par&aacute;metro es un valor num&eacute;rico o una constante con nombre tendremos que hacerlo al analizar varias funciones distintas (MODE, PAPER, PEN, LOCATE), podemos crear una funci&oacute;n auxiliar &quot;LeerValorOConst&quot; que analice si se trata de un n&uacute;mero, y, si no es as&iacute;, busque el valor en la tabla de s&iacute;mbolos, y as&iacute; nuestro fuente ser&aacute; un poco m&aacute;s compacto:</p>


<pre><code>
void analizarCPCMODE()
{
  miLexer.LeerSimbolo('(');
  string cadenaTemp = miLexer.ObtenerEnteroOIdentificador();
  int modo = miTablaSimb.LeerValorOConst(cadenaTemp);
  miLexer.LeerSimbolo(')');
  miLexer.LeerSimbolo(';');
  miGenerador.genCPCMODE( modo );
}
</code></pre>



<p>Con pocos cambios similares a ese, conseguir&iacute;amos que nuestro mini-compilador reconozca tanto valores num&eacute;ricos como constantes.</p>

<p><br>Como siempre, para m&aacute;s detalles, todo el c&oacute;digo est&aacute; en la p&aacute;gina del proyecto en Google Code:<br /><br /><a href="http://code.google.com/p/cpcpachi/">http://code.google.com/p/cpcpachi/</a></p>

<p align="right">(Volver al <a href="doc.html">&iacute;ndice</a>) </p>
</body>
</html>
